<?php

    class CacheUtils
    {
        const JS_CONTENT    = "js";
        const CSS_CONTENT   = "css";

        private static $externalMainCssDir = "/css";
        private static $cacheCssSubDir     = "css";
        private static $resourceCssSubDir  = "content/css";
        private static $cssFileExtension   = "css";

        private static $externalMainJsDir  = "/js";
        private static $cacheJsSubDir      = "js";
        private static $resourceJsSubDir   = "content/js";
        private static $jsFileExtension    = "js";

        private function __construct()
        {
        }

        /**
         * @param PageInfo $pageInfo
         * @param array $cssFiles
         * @return array
         */
        public static function GetPageCachedCssFiles( $pageInfo, $cssThemeFiles )
        {
            $cssFiles = array_merge( $cssThemeFiles, $pageInfo->stylesheets );
            $cachedCssFiles = self::GetCachedCssFiles( $pageInfo, $cssFiles );

            return $cachedCssFiles;
        }

        /**
         * Makes cached css file by specified file prefix and css files list.
         * @param PageInfo $pageInfo
         * @param array $cssFiles
         * @return array of cached css files URLs
         */
        public static function GetCachedCssFiles( $pageInfo, $cssFiles )
        {
            $prefix = $pageInfo->id;

            foreach ( $cssFiles as $key => $fileName )
            {
                if ( !empty( $fileName ) )
                {
                    $cssFiles[$key] = self::GetStylesheetSpriteFile( $fileName );
                }
            }

            if ( !RESOURCE_CACHE_ENABLE )
            {
                return self::FixFilePaths( $cssFiles, self::$externalMainCssDir );
            }

            $resultCssFiles = array();

            $preparedCssFiles = self::FixFilePaths( $cssFiles, self::$resourceCssSubDir);

            if ( !empty( $preparedCssFiles ) )
            {
                $cacheResourceInfo = new CacheResourceInfo();
                $cacheResourceInfo->prefix              = $prefix;
                $cacheResourceInfo->files               = $preparedCssFiles;
                $cacheResourceInfo->cacheSubDir         = self::$cacheCssSubDir;
                $cacheResourceInfo->fileExtention       = self::$cssFileExtension;
                $cacheResourceInfo->version             = CSS_VERSION;
                $cacheResourceInfo->contentType         = self::CSS_CONTENT;
                $cacheResourceInfo->updateCssResource   = true;
                $resultCssFiles[] = self::PrepareCacheFile( $cacheResourceInfo );
            }

            return $resultCssFiles;
        }

        /**
         * @param string $pageId
         * @param array $jsFiles
         * @param array $jsThemeFiles
         * @return array
         */
        public static function GetPageCachedJsFiles( $pageId, $jsFiles, $jsThemeFiles, $language = null )
        {
            $lngMessagesJsFiles = array();
            array_push( $lngMessagesJsFiles, PageConfig::GetLngMessagesJs($language) );
            $jsFiles = array_merge( $lngMessagesJsFiles, $jsThemeFiles, $jsFiles );

            $resultJsFileName = $pageId . "_" . Core::GetLanguage();
            $cachedJsFiles = self::GetCachedJsFiles( $resultJsFileName, $jsFiles );

            return $cachedJsFiles;
        }

        /**
         * Makes cached js file by specified file prefix and js files list.
         * @param string $prefix
         * @param array $jsFiles
         * @return array of cached js files URLs
         */
        public static function GetCachedJsFiles( $prefix, $jsFiles )
        {
            $resultJsFiles = array();

            if ( !RESOURCE_CACHE_ENABLE )
            {
                return self::FixFilePaths( $jsFiles, self::$externalMainJsDir );
            }

            $preparedJsFiles = self::FixFilePaths( $jsFiles, self::$resourceJsSubDir );

            if ( !empty( $preparedJsFiles ) )
            {
                $cacheResourceInfo = new CacheResourceInfo();
                $cacheResourceInfo->prefix              = $prefix;
                $cacheResourceInfo->files               = $preparedJsFiles;
                $cacheResourceInfo->cacheSubDir         = self::$cacheJsSubDir;
                $cacheResourceInfo->fileExtention       = self::$jsFileExtension;
                $cacheResourceInfo->version             = JS_VERSION;
                $cacheResourceInfo->contentType         = self::JS_CONTENT;
                $cacheResourceInfo->updateCssResource   = false;
                $resultJsFiles[] = self::PrepareCacheFile( $cacheResourceInfo );
            }

            return $resultJsFiles;
        }

        /**
         * Merges files.
         *
         * @param array $fileNames
         * @return string
         */
        public static function GetMergedFilesContent( $fileNames )
        {
            $result = "";

            if ( !empty( $fileNames ) )
            {
                foreach ( $fileNames as $fileName )
                {
                    $result .= file_get_contents( $fileName ) . "\n";
                }
            }

            return $result;
        }

        /**
         * Check file generated by Smartsprites exists
         *
         * @param string $stylesheet
         * @return string
         */
        public static function GetStylesheetSpriteFile( $stylesheet )
        {
            $CSS_SPRITE_SUFFIX = "_sprite";
            $CSS_SUB_DIR = "content";

            $file_info = pathinfo( $stylesheet );
            $dir_info = pathinfo( $file_info["dirname"] );
            $absolutePathSprite = ROOT_PATH . $CSS_SUB_DIR . '/css/sprites/' . $file_info["filename"] . $CSS_SPRITE_SUFFIX . '.css';
            $relativePathSprite = 'sprites/' . $file_info["filename"] . $CSS_SPRITE_SUFFIX . '.css';

            $cssSpriteFileName = $stylesheet;

            if ( file_exists( $absolutePathSprite ) )
            {
                $cssSpriteFileName = $relativePathSprite;
            }

            return $cssSpriteFileName;
        }

        public static function NormalizeResourcesPath( $content )
        {
            // Use current host for secure connections ( because CDN doesn't support https)
            // and when CDN is not enabled
            if ( Request::IsSecure() || !Core::Config()->server_url->use_cdn )
            {
                return $content;
            }

            $contentServerUrl = Core::Config()->server_url->content_server_url;

            return preg_replace( "/(\/images\/[^\"\'])/", $contentServerUrl . "$1", $content );
        }

        /**
         * @param CacheResourceInfo $cacheResourceInfo
         * @return string
         */
        private static function PrepareCacheFile( CacheResourceInfo $cacheResourceInfo )
        {
            $cacheFileOutputLink = '';
            $isEmptyResourceCacheInfo = !isset( $cacheResourceInfo ) || empty( $cacheResourceInfo );
            if ( $isEmptyResourceCacheInfo || empty( $cacheResourceInfo->files ) )
            {
                return $cacheFileOutputLink;
            }

            $cacheFileName = self::GenerateCacheFileName( $cacheResourceInfo );
            $cacheFileOutputLink = "/datacache/" . $cacheFileName;

            $isNeededRewriteFile = !file_exists( CACHE_DIR . $cacheFileName );
            if ( $isNeededRewriteFile )
            {
                self::RewirteCacheFile( $cacheResourceInfo, $cacheFileName );
            }

            return $cacheFileOutputLink;
        }

        /**
         * Rewrite cache file by merging files from $cacheResourceInfo and puts it's content to $cacheFileName
         *
         * @param CacheResourceInfo $cacheResourceInfo
         * @param string $cacheFileName
         */
        private static function RewirteCacheFile( CacheResourceInfo $cacheResourceInfo, $cacheFileName )
        {
            if ( !file_exists( CACHE_DIR . $cacheResourceInfo->cacheSubDir ) )
            {
                mkdir( CACHE_DIR . $cacheResourceInfo->cacheSubDir, 0770, true);
            }
            $mergingFile = self::GetMergedFilesContent( $cacheResourceInfo->files );

            $fileContent = self::MinifyContent( $mergingFile, $cacheResourceInfo->contentType );

            $cacheBusterNeeded = defined('CACHE_BUSTER_ENABLE')
                ? CACHE_BUSTER_ENABLE && ( $cacheResourceInfo->fileExtention == self::$cssFileExtension )
                : false;
            if ( $cacheBusterNeeded )
            {
                $cacheBuster = new CacheBuster(CacheBuster::CSS_TYPE);
                $fileContent = $cacheBuster->ModifyContent($fileContent);
            }

            file_put_contents( CACHE_DIR . $cacheFileName, $fileContent, LOCK_EX );
        }

        /**
         * Generates chache file name for merged file.
         *
         * @param CacheResourceInfo $cacheResourceInfo
         * @return string
         */
        private static function GenerateCacheFileName( CacheResourceInfo $cacheResourceInfo )
        {
            $key = self::GetCombinedFilesKey($cacheResourceInfo->files);
            $cacheFileName  = $cacheResourceInfo->cacheSubDir . "/" . $key . "_" . $cacheResourceInfo->version;
            $cacheFileName  = $cacheFileName . "." . $cacheResourceInfo->fileExtention;

            return $cacheFileName;
        }

        private static function GetCombinedFilesKey($files)
        {
            $files = array_unique($files);
            sort($files);

            // compute the key
            $key = md5(serialize($files));

            return $key;
        }

        /**
         * @return array
         */
        private static function FixFilePaths( $files, $subDir = "" )
        {
            $updatedFiles = array();
            if ( !empty( $files ) )
            {
                foreach ( $files as $value )
                {
                    if ( !empty( $value ) )
                    {
                        if ( UrlHelper::GetScheme( $value ) == '' )
                        {
                            $updatedFiles[] = $subDir . "/$value";
                        }
                        else
                        {
                            $updatedFiles[] = $value;
                        }
                    }
                }
            }

            return $updatedFiles;
        }

        /**
         * @param string $content
         * @param string $contentType
         * @return string
         */
        private static function MinifyContent( $content, $contentType )
        {
            if ( $contentType == self::CSS_CONTENT )
            {
                return cssmin::minify( $content );
            }
            if ( $contentType ==  self::JS_CONTENT )
            {
                return JSMin::minify( $content );
            }

            return $content;
        }
    }

?>